package work.thread_eg.concurrent.synchronized_eg;

import work.entity.User;

/**
 * 关于synchronized关键字的使用
 *
 * synchronized在hotSpot的实现是通过markword （8字节 64位) 实现的 jvm规范并未强制规定要怎么实现
 *
 * synchronized对某个对象加锁 锁的是对象 不是代码
 * 锁的信息是在对象里面的 o这个对象 的 markword里面
 * markword 包含 1 锁信息  2 GC信息  3 （分代年龄 4bit 最大15)  4 hashcode的值
 *
 * 1) 锁的分类 锁升级
 * 偏向锁： 非操作系统的重量级锁 线程给对象添加了标签（线程id) 内存包含了 之前当前线程的指针
 * 偏向锁 -> 轻量级锁 : 一个线程的时候是偏向锁 第二个线程来的时候 争夺资源升级到轻量级锁
 * 轻量级锁（自旋锁 无锁）： 有竞争 争夺方式（自旋 CAS 不行就再来一遍）每个线程的线程栈的lock Record会抢着把自己的指针贴到markword中
 *                          自旋锁是在用户态 不经过内核态 效率比重量级锁高 （lock 原子类也是自旋锁)
 * 自旋锁 -> 重量级锁： 竞争再加剧 自旋循环会高度占用用户态的CPU
 * 重量级锁：markword存储的是指向操作系统内核态的互斥量（重量级锁）的指针 每个重量级锁是有个队列的 其他线程会wait 不消耗CPU
 * PS : 执行时间长(加锁代码) 线程数多 尽量用系统锁 重量级锁 也就是synchronized
 *      执行时间短 线程数少 用自旋锁 自旋的线程不能太多 否则CPU就炸了 也就是原子类 lock等
 *
 * 2) synchronized的实现 底层也是基于汇编指令lock cmpxchg
 * 实现过程：
 * 1 java synchronized关键字
 * 2 字节码层面 monitorenter 和 monitorexit
 * 3 jvm运行时候 锁实现自动升级
 * 4 底层基于汇编 lock cmpxchg
 *
 * 3) 可重入性
 * 如果不可重入 会造成死锁
 * 两个synchronized的方法 m1和m2 m1中调用m2
 * 一个线程已经拥有了某个对象的锁 再次申请的时候 仍然会得到该对象的锁
 * 子类重写父类的synchronized方法 调用super方法 锁的是同一个对象 this对象
 *
 * 4) 异常和锁
 * 程序出现异常 默认锁是会释放的 其他线程就会拿到锁 会进入程序造成数据错乱 解决方法是主动catch就可以了
 *
 * 5) synchronized(Object)
 * 不能使用String常量 int Integer变量
 * String常量是只有一个 Integer变一下就会产生一个新对象
 *
 * 6) 非公平锁
 */
public class SynchronizedTest01 {

    private int count  = 10 ;
    Object o = new Object();
    User user = new User();

    public void m1() {
        // 任何线程要执行下面这段代码必须先要拿到o这个对象的锁
        synchronized (o) {
            count --;
            System.out.println(Thread.currentThread().getName() + " count = " + count);
        }
    }

    /**
     * synchronized方法 和 synchronized(this)是等值的 this是当前对象
     * synchronized静态方法相当于 synchronized(T.class)
     */
    public synchronized void m2() {
            count --;
            System.out.println(Thread.currentThread().getName() + " count = " + count);
    }

    public static void main(String[] args) {

    }
}
